package com.sh.data.engine.domain.shims.sql.function;

import com.sh.data.engine.domain.shims.sql.Context;
import com.sh.data.engine.domain.shims.sql.TerminalExpression;
import com.sh.data.engine.domain.shims.sql.select.RowMapper;
import lombok.Builder;
import org.apache.commons.lang3.StringUtils;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;

/**
 * @author：jingchen.hr
 * @descripion:
 * @data:12/21/20212:37 PM
 */
public class Functioner implements TerminalExpression {

    private final Context context;

    public Functioner() {
        this.context = new Context(null, null);
    }

    public Functioner(Context context) {
        this.context = context;
    }

    @Override
    public <E> List<E> list(RowMapper<E> rowMapper) throws SQLException {
        return context.list(rowMapper);
    }

    @Override
    public ResultSet list() throws SQLException {
        return context.list();
    }


    @Override
    public <E> E single(RowMapper<E> rowMapper) throws SQLException {
        return context.single(rowMapper);
    }

    public Function getFunction() {
        return new FunctionerFactory().create(context);
    }

    @Override
    public String toString() {
        return context.toString();
    }
}

interface Function {

    Context NVL(Collection<String> exprs);

    Context TO_DATE(Collection<String> exprs);
}

class HiveFunctioner extends Functioner implements Function {
    private final Context context;

    public HiveFunctioner(Context context) {
        this.context = context;
    }

    @Override
    public Context NVL(Collection exprs) {
        return context
            .appendWithLeftBracket("IFNULL")
            .appendWithRightBracket(StringUtils.join(exprs, ","));
    }

    @Override
    public Context TO_DATE(Collection exprs) {
        return null;
    }
}

class MySqlFunctioner extends Functioner implements Function {
    private final Context context;

    public MySqlFunctioner(Context context) {
        this.context = context;
    }

    @Override
    public Context NVL(Collection<String> exprs) {
        return new DefaultFunctioner().NVL(exprs);
    }

    @Override
    public Context TO_DATE(Collection<String> exprs) {
        return null;
    }
}

class OracleFunctioner extends Functioner implements Function {
    private final Context context;

    public OracleFunctioner(Context context) {
        this.context = context;
    }

    @Override
    public Context NVL(Collection<String> exprs) {
        return context
            .appendWithLeftBracket("IFNULL")
            .appendWithRightBracket(StringUtils.join(exprs, ","));
    }

    @Override
    public Context TO_DATE(Collection<String> exprs) {
        return null;
    }
}

class PostgresSqlFunctioner extends Functioner implements Function {
    private final Context context;

    public PostgresSqlFunctioner(Context context) {
        this.context = context;
    }

    @Override
    public Context NVL(Collection<String> exprs) {
        return new DefaultFunctioner().NVL(exprs);
    }

    @Override
    public Context TO_DATE(Collection<String> exprs) {
        return null;
    }
}

class SqlServerFunctioner extends Functioner implements Function {
    private final Context context;

    public SqlServerFunctioner(Context context) {
        this.context = context;
    }

    @Override
    public Context NVL(Collection<String> exprs) {
        return new DefaultFunctioner().NVL(exprs);
    }

    @Override
    public Context TO_DATE(Collection<String> exprs) {
        return null;
    }
}

class DB2Functioner extends Functioner implements Function {
    private final Context context;

    public DB2Functioner(Context context) {
        this.context = context;
    }

    @Override
    public Context NVL(Collection<String> exprs) {
        return new DefaultFunctioner().NVL(exprs);
    }

    @Override
    public Context TO_DATE(Collection<String> exprs) {
        return null;
    }
}

@Builder
class DefaultFunctioner extends Functioner implements Function {
    private final Context context;

    public DefaultFunctioner() {
        this.context = new Context(null, null);
    }

    public DefaultFunctioner(Context context) {
        this.context = context;
    }

    @Override
    public Context NVL(Collection exprs) {
        return context
            .appendWithLeftBracket("IFNULL")
            .appendWithRightBracket(StringUtils.join(exprs, ","));
    }

    @Override
    public Context TO_DATE(Collection exprs) {
        return null;
    }
}

class FunctionerFactory {
    Function create(Context context) {
        switch (context.getDatabase()) {
            case HIVE:
                // return new HiveFunctioner();
            case MYSQL:
                // return new  MySqlFunctioner();
            case ORACLE:
                // return new OracleFunctioner();
            case POSTGRESQL:
                // return new HiveFunctioner();
            case SAP:
                // return new PostgresSqlFunctioner();
            case SQLSERVER:
                // return new SqlServerFunctioner();
            case DB2:
                // return new DB2Functioner();
            default:
                return new DefaultFunctioner(context);
        }
    }
}

